package com.zjy.business.system.manager.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zjy.business.system.common.SysPermissionCommon;
import com.zjy.business.system.dao.SysUserDao;
import com.zjy.business.system.dao.SysUserRoleDao;
import com.zjy.business.system.domain.entity.SysUser;
import com.zjy.business.system.domain.entity.SysUserRole;
import com.zjy.business.system.domain.manager.form.ManagerSysUserSaveOrUpdateForm;
import com.zjy.business.system.domain.manager.query.ManagerListPageSysUserQuery;
import com.zjy.business.system.domain.manager.vo.ManagerListPageSysUserVo;
import com.zjy.business.system.manager.service.ManagerSysUserService;
import com.zjy.common.constant.StatusEnums;
import com.zjy.common.constant.StringConstant;
import com.zjy.common.utils.ConvertBeanUtils;
import com.zjy.common.utils.StreamUtils;
import com.zjy.web.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author yxb
 * create_time: 2024-10-22 14:57
 * description: 
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ManagerSysUserServiceImpl implements ManagerSysUserService {

    final private SysUserDao sysUserDao;

    final private SysUserRoleDao sysUserRoleDao;

    final private SysPermissionCommon sysPermissionCommon;

    @Override
    @Transactional
    public void saveOrUpdate(ManagerSysUserSaveOrUpdateForm form) {
        // 校验入参
        checkSaveOrUpdate(form);
        Long id = form.getId();
        if (Objects.isNull(id)) {
            SysUser convert = ConvertBeanUtils.convert(form, SysUser.class);
            // 密码加密
            convert.setPassword(passwordEncode(form.getPassword()));
            convert.setId(IdUtil.getSnowflakeNextId());
            sysUserDao.save(convert);
            // 保存角色
            saveOrUpdateUserRole(convert.getId(), form.getRoleIdList(), false);
        } else {
            SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, id);
            if (Objects.isNull(sysUser)) {
                throw BusinessException.EXCEPTION("用户不存在");
            }
            sysUser.setAccount(form.getAccount());
            sysUser.setNickName(form.getNickName());
            sysUser.setEmail(form.getEmail());
            sysUser.setPhone(form.getPhone());
            sysUser.setSex(form.getSex());
            sysUser.setAvatar(form.getAvatar());
            if (!StringUtils.equals(form.getPassword(), sysUser.getPassword())) {
                sysUser.setPassword(passwordEncode(form.getPassword()));
            }
            sysUser.setStatus(form.getStatus());
            sysUser.setRemark(form.getRemark());
            sysUserDao.updateByIdUpdateCache(sysUser, SysUser::getId, id);
            // 更新用户角色关联信息
            saveOrUpdateUserRole(id, form.getRoleIdList(), true);
            if (Objects.equals(form.getStatus(), StatusEnums.PUBLIC_STATUS_STOP.getStatus())) {
                // 如果状态设置为关闭将指定账号踢下线
                StpUtil.kickout(form.getId());
            }
            sysPermissionCommon.clearByUserId(sysUser.getId());
            sysUserRoleDao.delCache(SysUserRole::getUserId, sysUser.getId());
        }
    }


    /**
     * 新增或更新用户角色关联信息
     * @param userId 用户id
     * @param roleIdList 角色id列表
     * @param clear 是否清空角色
     */
    public void saveOrUpdateUserRole(Long userId, List<Long> roleIdList, boolean clear) {
        if (clear) {
            sysUserRoleDao.removeByUserId(userId);
        }
        if (ObjectUtils.isNotEmpty(roleIdList)) {
            List<SysUserRole> sysUserRoleList = roleIdList.stream().map(item -> {
                SysUserRole sysUserRole = new SysUserRole();
                sysUserRole.setRoleId(item);
                sysUserRole.setUserId(userId);
                return sysUserRole;
            }).toList();
            sysUserRoleDao.saveBatch(sysUserRoleList);
        }
    }

    /**
     * 密码加密
     * @param password
     * @return
     */
    private String passwordEncode(String password) {
        return DigestUtil.md5Hex(password);
    }


    /**
     * 校验新增/修改入参
     * @param form
     */
    private void checkSaveOrUpdate(ManagerSysUserSaveOrUpdateForm form) {
        sysUserDao.lambdaQuery()
                .eq(SysUser::getAccount, form.getAccount())
                .ne(Objects.nonNull(form.getId()), SysUser::getId, form.getId())
                .oneOpt()
                .ifPresent(user -> {
                    throw BusinessException.EXCEPTION("已存在相同用户名");
                });
    }

    @Override
    public void remove(Long id) {
        SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, id);
        if (Objects.nonNull(sysUser)) {
            sysUserDao.removeByIdDeleteCache(id, SysUser::getId, id);
            // 清除用户角色绑定关系
            sysUserRoleDao.removeByUserId(id);
            sysPermissionCommon.clearByUserId(sysUser.getId());
            StpUtil.kickout(sysUser.getId());
        }
    }

    @Override
    public PageInfo<ManagerListPageSysUserVo> listPageSysUser(ManagerListPageSysUserQuery query) {
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return PageInfo.of(sysUserDao.listPageSysUser(query));
    }

    @Override
    public void resetPassword(Long userId) {
        SysUser sysUser = sysUserDao.findCacheOne(SysUser::getId, userId);
        if (Objects.isNull(sysUser)) {
            throw BusinessException.EXCEPTION("用户不存在");
        }
        sysUser.setPassword(passwordEncode(StringConstant.DEFAULT_PASSWORD));
        sysUserDao.updateByIdUpdateCache(sysUser, SysUser::getId, userId);
    }

    @Override
    public List<SysUser> userDownList() {
        List<Long> ids = StreamUtils.toList(sysUserDao
                .lambdaQuery()
                .orderByDesc(SysUser::getId)
                .select(SysUser::getId)
                .list(), SysUser::getId);
        Map<Long, SysUser> dataMap = sysUserDao.findCacheOneByMoreParam(SysUser::getId, ids);
        return StreamUtils.toList(ids, dataMap::get);
    }
}
